package src.application.Doppelkopf;

import java.io.*;
import java.net.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Klasse, um den Server zu realisieren
 * @author b.osterholt
 *
 */
public class Server {
    static Spieler spieler[] = new Spieler[4];
    static Socket clients[] = new Socket[4];
    static ArrayList<Tisch> tische = new ArrayList<>();
    static private ServerSocket listenSocket;
    static private int port=6564;
    static private int anz=0;
    static private HashMap <Integer,Connection> connections=new HashMap<Integer,Connection>();
    static protected HashMap <Integer,String> usernames=new HashMap<Integer,String>();

    public static void main(String[] args) {
//bei Programmbeenden muss noch listensocket, geschlossen werden 
        try{
            System.out.println("Server gestartet!");
            listenSocket = new ServerSocket(port);
            System.out.println("IP: "+listenSocket.getInetAddress()); 
            // Bianca 134.94.248.187; localhost: 127.0.0.1; Tobi: 192.94.145.12
            System.out.println("Port: " + port);
            ServerFrame serverFr = new ServerFrame();
            serverFr.setVisible(true);
         
            while(anz < 4){    //Warte auf bis zu vier Spieler (sonst stattdessen while(true))
                byte[] b = new byte[100];
                String user="";
                ByteArrayOutputStream bout = new ByteArrayOutputStream();
                
                //Client verbunden
            	Socket clientSocket = listenSocket.accept(); 
                anz++;  
		System.out.println("Neue Verbindung! Erzeuge Connection ...");
		Connection c = new Connection(clientSocket, anz-1); //anz = 0,1,2,3
                DataOutputStream out = new DataOutputStream(clientSocket.getOutputStream());
                DataInputStream in = new DataInputStream(clientSocket.getInputStream());

                //Username empfangen
                if (in.read(b) != -1) { //-1 bei Fehler
                    bout.write(b);  //bytearray auf bytearrayoutputstream schreiben
                    user = bout.toString();
                    user = user.trim();
                    System.out.println("Mit Client \""+ user+"\" verbunden.");
		}
                
                PrintWriter pW =new PrintWriter(new OutputStreamWriter(out));
                //Begruessungs-Message +Spielernr senden
                pW.write("Hallo " + user+"!#Nr#" + (anz-1)+"#"+"$END$");
                pW.flush();
                //out.write(("Hallo " + user+"!#Nr#" + anz+"#"+"$END$"").getBytes()); 
                      
                Spieler sp= new HSpieler();
                sp.setName(user);
                spieler[anz-1] = sp;
                clients[anz-1] = clientSocket;
                c.start(); //Connection c
		connections.put(anz-1, c);
		usernames.put(anz-1, user);
                serverFr.aktualisere(usernames);
//                in.close(); out.close(); -> nur benoetigt, wenn pW nicht verwendet
                
//!!! Abfragen, ob ein spieler "Spiel starten" klickt -> while verlassen !!!
//aber erst sobald die ki fertig ist
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                
            }//Ende while (anz < 4)
        tische.add(new Tisch(spieler)); //Tisch in Arraylist speichern
        while(true){
            tische.get(0).spiele();
            try {Thread.sleep(100);
            } catch (InterruptedException ex) {
                Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
            }
            tische.get(0).neueRunde();
        }
        
        
        }catch (java.net.ConnectException e2){
            System.err.println("connect exception:"+e2.getMessage()); 
            e2.printStackTrace();
	}catch (IOException e1) {
            System.err.println("Listen :"+e1.getMessage());
            e1.printStackTrace();
	}catch (Exception e){
            System.err.println("Server-try in main:"+e.getMessage());
            e.printStackTrace();
        }//ende Try-catch
    } //ende der Main
    
    /**
     * sendet einen String
     * 
     * B -> Beginn + Handkarten jedes Spielers + Namen aller Spieler in der Reihenfolge ab mir
     * H -> Karte spielen    
     * S -> Karte wurde gespielt   
     * A -> Ansage wurde gemacht 
     * G -> Spielername, der den Stich gewonnen hat
     * 
     * @param nr:   An wen gesendet werden soll
     * @param c :   Art der Nachricht
     * @param s :   String, der gesendet werden soll
     */
    public static void sende(int nr, char c, String s){
        System.out.println("SENDE ETWAS an "+nr+": "+s);
        try {Thread.sleep(40);
        } catch (InterruptedException ex) {
            Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
        }
        try {
            PrintWriter pW =new PrintWriter(new OutputStreamWriter(connections.get(nr).out));
            String sende="";
            switch (c){
                case 'B': 
                    String namen="";
                    for (int i=0; i<4; i++){ //Spielernamen zusammenstellen von jeder Position aus
                        namen+=spieler[(nr+i)%4].getName()+"#";
                    }
                    sende = s+namen+"$END$";
                    pW.write(sende);
                    pW.flush();
                    //(connections.get(nr).out).write((sende).getBytes());
                    break;
                case 'H': 
                    pW.write(s);
                    pW.flush();
                    //(connections.get(nr).out).write((s+"$END$").getBytes());
                    break;
                case 'S':
                    sende =  s+"$END$";
                    pW.write(sende);
                    pW.flush();
                    break;
                case 'G':
                    sende =  "G#"+spieler[Integer.parseInt(s.split("#")[1])].getName()+"#$END$";
                    pW.write(sende);
                    pW.flush();
                    break;
                case 'V':
                    sende = s+"$END$";
                    pW.write(sende);
                    pW.flush();
                    break;
                case 'A':
                    sende = s+"$END$";
                    pW.write(sende);
                    pW.flush();
                    break;
                case 'R':
                    sende = "R#"+s+"$END$";
                    pW.write(sende);
                    pW.flush();
                    break;
                default: System.out.println(c + " nichts gesendet");
            }
        //} catch (IOException e) {System.out.println("Send :"+e.getMessage()); e.printStackTrace();
        } catch (NullPointerException e) {System.out.println(e.getMessage() + e.getLocalizedMessage()); e.printStackTrace();
        } catch (Exception e) {System.out.println("Send :"+e.getMessage()); e.printStackTrace();}   
    }
    
    /**
     * Empfaengt eine Nachricht vom Client
     * @param nr:   Von diesem Spieler soll eine Nachricht empfangen werden
     * @return  :   Nachricht, die empfangen wurde
     */
    public static String empfange(int nr){   
        String text;
//            byte[] b = new byte[100]; 
//            ByteArrayOutputStream bout = new ByteArrayOutputStream();
        System.out.print("EMPFANGE ETWAS von"+nr+": ");
        try {            
//hier aendern -> empfange bis was da ist (solange leere while)            
            
            BufferedReader bufferedReader =new BufferedReader(new InputStreamReader(connections.get(nr).in));
            char[] buffer = new char[100];
            //blockiert bis Nachricht empfangen
            int anzahlZeichen = bufferedReader.read(buffer, 0, 100);
            text = new String(buffer, 0, anzahlZeichen);
            //while (connections.get(nr).in.read() == -1) {  }            
//            bout.write(b);  //bytearray auf bytearrayoutputstream schreiben
//            text = bout.toString();
//            bout.flush();
                  
            return empfange(text, nr); //String weitergeben
        } catch (IOException e) {System.out.println("Recieve :"+e.getMessage());}
        return "-1";
    }
    /**
     * Verarbeitet die empfangene Nachricht
     * @param text: Nachricht, die empfangen wurde
     * @param nr  : Von diesem Spieler wurde die Nachricht empfangen
     * @return    : Nachricht, die empfangen wurde
     */
    public static String empfange(String text, int nr){
        System.out.println("+++"+text);

        String s;
        text = text.trim();
        String[] split = text.split("#");
        char c = split[0].charAt(0);
        switch (c){
            case 'H': //Karte wurde gespielt -> mit S weiterversenden
                s = "S#"+ nr + text.substring(1);
                for (int i=0; i<4; i++) { sende((nr+i)%4, 'S', s); }
                break;
            case 'A': //Ansage wurde gemacht
                s = "A#"+ spieler[nr].getName() + text.substring(1);
                for (int i=0; i<4; i++) { sende((nr+i)%4, 'A', s); }
                break;
            case 'V': //Vorbehalt wurde gemacht
                System.out.println("vorher:\t"+tische.get(0).anzV);
                ++tische.get(0).anzV;   //sicherstellen, dass jeder spieler geantwortet hat
                System.out.println("nachher:\t"+tische.get(0).anzV);
                
                if(split.length==7){
                    text= text.split("\\$")[2] + "$END$";
                    empfange(text, nr);
                    return text;
                }
                System.out.println("Vorbehalt von "+ nr+ ": "+text);
                spieler[nr].setVorbehalte(Integer.parseInt(split[1]),Integer.parseInt(split[2]));
                break;
                
            default: 
                System.out.println("\n\netwas anderes empfangen\n+++" + text+"+++");
                return "-1";
            }
        return text;
    }
}
